package org.chen.aao.gateway.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.chen.aao.gateway.utils.JwtUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.*;

@Slf4j
@Component
@RequiredArgsConstructor
public class AuthFilter implements GlobalFilter, Ordered {
    
    private final JwtUtil jwtUtil;
    private final ObjectMapper objectMapper = new ObjectMapper();
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    
    // 白名单路径（不需要认证）
    private static final List<String> WHITE_LIST = Arrays.asList(
            "/apis/auth/user/register",
            "/apis/auth/user/login",
            "/apis/auth/user/logout",
            "/apis/auth/user/refresh-token",
            "/apis/app/version/check-update",
            "/apis/auth/user/send-register-code",
            "/apis//auth/user/send-reset-code",
            "/apis/auth/user/reset-password",
            "/apis/app/analytics/events",
            "/apis/subs/products",
            "/apis/health/**",
            "/apis/doc/**",
            "/swagger-ui/**",
            "/apis/subs/v3/api-docs/**",
            "/apis/auth/v3/api-docs/**",
            "/apis/file/v3/api-docs/**"
    );
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        
        // 检查是否在白名单中
        if (isWhitelisted(path)) {
            return chain.filter(exchange);
        }
        
        // 获取token
        String token = getToken(request);
        if (token == null || token.isEmpty()) {
            return unauthorized(exchange.getResponse(), "缺少认证token");
        }
        
        // 验证token
        if (jwtUtil.validateToken(token)) {
            return unauthorized(exchange.getResponse(), "无效的token");
        }
        
        // 从token中获取用户ID
        Long userId = jwtUtil.getUserIdFromToken(token);
        if (userId == null) {
            return unauthorized(exchange.getResponse(), "无法解析用户信息");
        }
        
        // 将用户ID添加到请求头中，传递给下游服务
        ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-User-Id", String.valueOf(userId))
                .header("X-Auth-Token", token)
                .build();
        
        ServerWebExchange mutatedExchange = exchange.mutate()
                .request(mutatedRequest)
                .build();
        
        return chain.filter(mutatedExchange);
    }
    
    private boolean isWhitelisted(String path) {
        return WHITE_LIST.stream()
                .anyMatch(pattern -> pathMatcher.match(pattern, path));
    }
    
    private String getToken(ServerHttpRequest request) {
        List<String> headers = request.getHeaders().get("Authorization");
        if (headers != null && !headers.isEmpty()) {
            String authHeader = headers.get(0);
            if (authHeader.startsWith("Bearer ")) {
                return authHeader.substring(7);
            }
        }
        
        // 也可以从查询参数中获取token（用于WebSocket等场景）
        String queryToken = request.getQueryParams().getFirst("token");
        if (queryToken != null && !queryToken.isEmpty()) {
            return queryToken;
        }
        
        return null;
    }
    
    private Mono<Void> unauthorized(ServerHttpResponse response, String message) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        
        Map<String, Object> result = new HashMap<>();
        result.put("code", 401);
        result.put("message", message);
        result.put("timestamp", System.currentTimeMillis());
        
        try {
            byte[] bytes = objectMapper.writeValueAsBytes(result);
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            return response.writeWith(Mono.just(buffer));
        } catch (Exception e) {
            log.error("Error writing response", e);
            return response.setComplete();
        }
    }
    
    @Override
    public int getOrder() {
        return -100;
    }
}